<?php

declare (strict_types=1);

namespace lgdz\hyperf;

use Closure;
use Hyperf\Contract\PaginatorInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Context;
use lgdz\Factory;
use lgdz\hyperf\exception\BusinessException;
use lgdz\lib\HttpResponse;
use lgdz\object\Body;
use lgdz\object\Query;
use Psr\Log\LoggerInterface;
use Psr\SimpleCache\InvalidArgumentException;

/**
 * Class Tools 助手
 * @package lgdz\hyperf
 */
class Tools
{
    /**
     * 数据库查询分页
     * @param PaginatorInterface $paginate
     * @param Closure|null $closure
     * @return array
     */
    public static function P(PaginatorInterface $paginate, Closure $closure = null): array
    {
        return [
            'total' => $paginate->total(),
            'pages' => $paginate->lastPage(),
            'items' => is_null($closure) ? $paginate->items() : array_map($closure, $paginate->items())
        ];
    }

    /**
     * 输入
     * @return RequestInterface|mixed
     */
    public static function I()
    {
        return ApplicationContext::getContainer()->get(RequestInterface::class);
    }

    /**
     * 输出
     * @return ResponseInterface|mixed
     */
    public static function O()
    {
        return ApplicationContext::getContainer()->get(ResponseInterface::class);
    }

    /**
     * 响应JSON
     * @return HttpResponse
     */
    public static function R(): HttpResponse
    {
        return static::F()->response;
    }

    /**
     * 缓存控制对象
     * @return mixed|\Psr\SimpleCache\CacheInterface
     */
    public static function C()
    {
        return ApplicationContext::getContainer()->get(\Psr\SimpleCache\CacheInterface::class);
    }

    /**
     * 缓存设置
     * @param string $key
     * @param $value
     * @param null $ttl
     * @return bool
     */
    public static function C_set(string $key, $value, $ttl = null): bool
    {
        try {
            return static::C()->set($key, $value, $ttl);
        } catch (InvalidArgumentException $e) {
            static::E($e->getMessage());
        }
    }

    /**
     * 缓存读取
     * @param $key
     * @return mixed
     */
    public static function C_get($key)
    {
        try {
            return static::C()->get($key);
        } catch (InvalidArgumentException $e) {
            static::E($e->getMessage());
        }
    }

    /**
     * 异常抛出
     * @param string $msg
     * @return mixed
     */
    public static function E(string $msg)
    {
        throw new BusinessException($msg);
    }

    /**
     * 接口正常返回
     * @param null $data
     * @return \Psr\Http\Message\ResponseInterface
     */
    public static function Ok($data = null)
    {
        return static::O()->json(
            static::R()->ok($data)
        );
    }

    /**
     * 接口异常返回
     * @param string $message
     * @param int $status
     * @return \Psr\Http\Message\ResponseInterface
     */
    public static function Bad(string $message = 'Error', int $status = 0)
    {
        return static::O()->json(
            static::R()->bad($message, $status)
        );
    }

    /**
     * 工具类
     * @return Factory
     */
    public static function F()
    {
        return Factory::container();
    }

    /**
     * 文件日志操作对象
     * @param string $name
     * @return LoggerInterface
     */
    public static function Log(string $name = 'log')
    {
        return ApplicationContext::getContainer()->get(\Hyperf\Logger\LoggerFactory::class)->get($name);
    }

    public static function Query(array $append = [])
    {
        $query = new Query(Tools::I()->getQueryParams());
        if (!empty($append)) {
            foreach ($append as $key => $value) {
                $query->$key = $value;
            }
        }
        return $query;
    }

    public static function Body(array $append = [])
    {
        $body = new Body(Tools::I()->getParsedBody());
        if (!empty($append)) {
            foreach ($append as $key => $value) {
                $body->$key = $value;
            }
        }
        return $body;
    }

    public static function container()
    {
        return ApplicationContext::getContainer();
    }

    public static function Context(string $name, $value = null)
    {
        if (is_null($value)) {
            return Context::get($name);
        } else {
            Context::set($name, $value);
        }
    }

    /**
     * 资源保存路径
     * @param string $type
     * @param string $filename
     * @return string
     */
    public static function StoragePath(string $type, string $filename)
    {
        $dirs = sprintf('%s/%s/', $type, date('Y-m-d'));
        !is_dir(static::AbsPath($dirs)) && mkdir(static::AbsPath($dirs), 0777, true);
        return $dirs . $filename;
    }

    /**
     * 资源本地绝对路径
     * @param string $path
     * @return string
     */
    public static function AbsPath(string $path)
    {
        return BASE_PATH . '/storage/' . $path;
    }

    /**
     * 数据结果缓存
     * @param string $key
     * @param int $ttl
     * @param Closure $loadData
     * @param bool $force
     * @return int|string|array
     */
    public static function CacheData(string $key, \Closure $loadData, int $ttl = 7200, bool $force = false)
    {
        $time = time();
        $data = static::C_get($key);
        if (!$data || $force) {
            $data['data'] = $loadData();
            $data['expire'] = $time + $ttl;
            static::C_set($key, $data);
        } elseif (isset($data['expire']) && $data['expire'] < $time) {
            go(function () use ($key, $ttl, $time, $loadData) {
                $data['data'] = $loadData();
                $data['expire'] = $time + $ttl;
                static::C_set($key, $data);
            });
        }
        return $data['data'];
    }

    /**
     * 生成数据库排序字段值
     * @param Query $query
     * @param string $default
     * @return string
     */
    public static function BuildOrder(Query $query, string $default = 'id')
    {
        $order_methods = [
            'ascend'  => 'asc',
            'descend' => 'desc'
        ];
        if ($query->sortField && $query->sortOrder) {
            return "{$query->sortField} {$order_methods[$query->sortOrder]}";
        } else {
            return "{$default} desc";
        }
    }
}